#ifndef BASIC_PRIMITIVES_HPP
#define BASIC_PRIMITIVES_HPP

#include "typedefs.hpp"
#include <vl/vec.hpp>
#include <vl/rect.hpp>

template< typename BitmapT, typename BlitterT >
void putPixel( BitmapT* bitmap, const vl::ivec& pos, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	if ( !bitmap->clip.inside(pos) ) return;
	unsigned char* data = bitmap->data;
	data += bitmap->pitch * pos.y + pos.x * BitmapT::SizeOfPixel;
	blitter.blitColorToPixel( *reinterpret_cast< typename BitmapT::ColorType* >(data), color );
}

template< typename BitmapT, typename BlitterT >
void hLine( BitmapT* bitmap, vl::ivec pos, unsigned int w, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	if ( pos.y < bitmap->clip.y1 || pos.y >= bitmap->clip.y2 ) return;
	int x2 = pos.x + w;
	if ( pos.x < bitmap->clip.x1 )
	{
		pos.x = bitmap->clip.x1;
	}
	if ( x2 > bitmap->clip.x2 )
	{
		x2 = bitmap->clip.x2;
	}
	if ( pos.x >= x2 ) return;
	
	w = x2 - pos.x;
	
	unsigned char* data = bitmap->data;
	data += bitmap->pitch * pos.y + pos.x * BitmapT::SizeOfPixel;
	blitter.blitColorToBuffer( reinterpret_cast< typename BitmapT::ColorType* >(data), color, w );
}

template< typename BitmapT, typename BlitterT >
void vLine( BitmapT* bitmap, vl::ivec pos, unsigned int h, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	if ( pos.x < bitmap->clip.x1 || pos.x >= bitmap->clip.x2 ) return;
	int y2 = pos.y + h;
	if ( pos.y < bitmap->clip.y1 )
	{
		pos.y = bitmap->clip.y1;
	}
	if ( y2 > bitmap->clip.y2 )
	{
		y2 = bitmap->clip.y2;
	}
	if ( pos.y >= y2 ) return;
	
	h = y2 - pos.y;
	
	unsigned char* data = bitmap->data;
	data += bitmap->pitch * pos.y + pos.x * BitmapT::SizeOfPixel;
	for ( ; h; --h, data += bitmap->pitch )
		blitter.blitColorToPixel( *reinterpret_cast< typename BitmapT::ColorType* >(data), color );
}

template< typename BitmapT, typename BlitterT >
void rectFill( BitmapT* bitmap, vl::rect rect, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	rect &= bitmap->clip;
	if ( rect.empty() ) return;
	unsigned char* data = bitmap->data;
	unsigned int w = rect.width();
	data += bitmap->pitch * rect.y1 + rect.x1 * BitmapT::SizeOfPixel;
	for ( unsigned int y = rect.height(); y; --y, data += bitmap->pitch )
		blitter.blitColorToBuffer( reinterpret_cast< typename BitmapT::ColorType* >(data), color, w );
}

template< typename BitmapT, typename BlitterT >
void blendToColor( BitmapT* bitmap, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	unsigned char* data = bitmap->data;
	for ( unsigned int y = bitmap->h; y; --y, data += bitmap->pitch )
		blitter.blitColorToBuffer( reinterpret_cast< typename BitmapT::ColorType* >(data), color, bitmap->w );
}

template< typename DstBitmapT, typename SrcBitmapT, typename BlitterT >
void blit( DstBitmapT* dst, SrcBitmapT* src, vl::ivec dstPos, vl::ivec srcPos, int w, int h, BlitterT& blitter )
{

	if ( (srcPos.x >= src->w) || (srcPos.y >= src->h) || (dstPos.x >= dst->clip.x2) || (dstPos.y >= dst->clip.y2))
		return;
	
	if ( srcPos.x < 0 ) {
		w += srcPos.x;
		dstPos.x -= srcPos.x;
		srcPos.x = 0;
	}
	
	if ( srcPos.y < 0 ) {
		h += srcPos.y;
		dstPos.y -= srcPos.y;
		srcPos.y = 0;
	}
	
	if (srcPos.x+w > src->w)
		w = src->w - srcPos.x;

	if (srcPos.y+h > src->h)
		h = src->h - srcPos.y;

	if (dstPos.x < dst->clip.x1) {
		dstPos.x -= dst->clip.x1;
		w += dstPos.x;
		srcPos.x -= dstPos.x;
		dstPos.x = dst->clip.x1;
	}

	if (dstPos.y < dst->clip.y1) {
		dstPos.y -= dst->clip.y1;
		h += dstPos.y;
		srcPos.y -= dstPos.y;
		dstPos.y = dst->clip.y1;
	}

	if (dstPos.x+w > dst->clip.x2)
		w = dst->clip.x2 - dstPos.x;

	if (dstPos.y+h > dst->clip.y2)
		h = dst->clip.y2 - dstPos.y;

	if ((w <= 0) || (h <= 0))
		return;
	
	unsigned char* dstData = dst->data;
	unsigned char* srcData = src->data;
	dstData += dst->pitch * dstPos.y + dstPos.x * DstBitmapT::SizeOfPixel;
	srcData += src->pitch * srcPos.y + srcPos.x * SrcBitmapT::SizeOfPixel;
	for ( ; h; --h, dstData += dst->pitch, srcData += src->pitch )
	{
		blitter.blitBufferToBuffer( reinterpret_cast< typename DstBitmapT::ColorType* >(dstData),
									reinterpret_cast< typename SrcBitmapT::ColorType* >(srcData),
									w );
	}
}

#endif // BASIC_PRIMITIVES_HPP
